package jmine.tec.web.wicket.component.menu;

import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.Map;

import jmine.tec.utils.collection.FilteredCollection;
import jmine.tec.utils.collection.Predicate;
import jmine.tec.web.wicket.component.menu.cfg.MenuConfig;
import jmine.tec.web.wicket.component.menu.cfg.MenuConfigItem;

import org.apache.commons.lang.StringUtils;
import org.apache.wicket.markup.ComponentTag;
import org.apache.wicket.markup.MarkupStream;
import org.apache.wicket.markup.html.WebComponent;
import org.apache.wicket.markup.parser.XmlTag;

/**
 * Componente para criação de menus.
 * 
 * @author katsuo.ogawa
 * @date Jul 5, 2011
 */
public class JSCookMenuPanel extends WebComponent implements MenuPanel {

    private String jsonMenu = null;

    private Map<String, String[]> pagePathMap = new HashMap<String, String[]>();

    /**
     * Construtor
     * 
     * @param id id
     * @param config config
     */
    public JSCookMenuPanel(String id, MenuConfig config) {
        super(id);
        this.jsonMenu = this.createJSONMenu(config);
        LinkedList<String> parentPath = new LinkedList<String>();
        for (MenuConfigItem child : config.getChildren()) {
            this.populatePageMap(child, parentPath);
        }
    }

    /**
     * Popula o mapa de páginas
     * 
     * @param item item
     * @param parentPath parentPath
     */
    private void populatePageMap(MenuConfigItem item, LinkedList<String> parentPath) {
        parentPath.add(item.getLabel());
        if (item.hasPage()) {
            this.pagePathMap.put(item.getPage().getPackage().getName(), parentPath.toArray(new String[0]));
        }
        for (MenuConfigItem child : item.getChildren()) {
            this.populatePageMap(child, parentPath);
        }
        parentPath.removeLast();
    }

    /**
     * {@inheritDoc}
     */
    @Override
    protected void onComponentTag(ComponentTag tag) {
        super.onComponentTag(tag);
        tag.setType(XmlTag.OPEN);
    }

    /**
     * {@inheritDoc}
     */
    @Override
    protected void onComponentTagBody(final MarkupStream markupStream, final ComponentTag openTag) {
        this.replaceComponentTagBody(markupStream, openTag, this.jsonMenu);
    }

    /**
     * Cria o menu JSON
     * 
     * @param config config
     * @return json
     */
    private String createJSONMenu(MenuConfig config) {
        StringBuilder builder = new StringBuilder();
        builder.append("<div id=\"jsCookMenuDiv\" class=\"menu_div\"></div>\n");
        builder.append("\n<script type=\"text/javascript\">\n");
        builder.append("    var applicationMenu =\n");
        builder.append("[\n");
        Iterator<MenuConfigItem> children = new FilteredCollection<MenuConfigItem>(config.getChildren(), new Predicate<MenuConfigItem>() {
            public boolean matches(MenuConfigItem e) {
                return e.isVisible();
            }
        }).iterator();
        while (children.hasNext()) {
            MenuConfigItem child = children.next();
            this.renderMenuItem(builder, "", "", child);
            if (children.hasNext()) {
                builder.append(",\n");
            }
        }
        builder.append("];\n");
        builder.append("    cmDraw('jsCookMenuDiv', applicationMenu, 'hbr', cmThemeGray);\n");
        builder.append("</script>\n");
        return builder.toString();
    }

    /**
     * Cria o item de menu em JSON
     * 
     * @param builder builder
     * @param prefix prefix
     * @param parentPath parentPath
     * @param item item
     */
    protected void renderMenuItem(StringBuilder builder, String prefix, String parentPath, MenuConfigItem item) {
        String url = item.createURL(parentPath) == null ? "null" : "'" + item.createURL(parentPath) + "'";
        String target = StringUtils.isEmpty(item.getAction()) ? "null" : "'iframe_cont'";
        builder.append(String.format("%s[null, '%s', %s, %s, null", prefix, item.getLabel(), url, target));
        if (item.hasChildren()) {
            builder.append(",\n");
        }
        Iterator<MenuConfigItem> children = new FilteredCollection<MenuConfigItem>(item.getChildren(), new Predicate<MenuConfigItem>() {
            public boolean matches(MenuConfigItem e) {
                return e.isVisible();
            }
        }).iterator();
        while (children.hasNext()) {
            MenuConfigItem subItem = children.next();
            String nextPath = StringUtils.isEmpty(parentPath) ? item.getLabel() : parentPath + MenuPanel.SEPARATOR + item.getLabel();
            this.renderMenuItem(builder, prefix + "\t", nextPath, subItem);
            if (children.hasNext()) {
                builder.append(",\n");
            }
        }
        builder.append("]");
    }

    /**
     * {@inheritDoc}
     */
    public String[] getPagePath(Class pageClass) {
        return this.pagePathMap.get(pageClass.getPackage().getName());
    }
}
